#include "swear.h"
#include "lang.h"
#include "script/scripthelper.h"

#include "util/mmgr.h"		
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging

#include <algorithm>
using namespace lang;
using namespace script;


Swear& Swear::Instance()
{
	static Swear Inst;
	return Inst;
}

Swear::Swear()
{

}

Swear::~Swear()
{

}

bool	Swear::Load(const std::string& File)
{
	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, File))
	{
		_LOG(MSG_ERROR, "Unable to load swear words " << File << "!");
		 LuaPlus::LuaState::Destroy( pScript );
		 return false;
	} else
	{
		LuaPlus::LuaObject	SwearFilter = ScriptHelper::GetObj(*pScript, "Swear");
		if (SwearFilter.IsTable())
		{
			for (int i=0; i<SwearFilter.GetTableCount(); i++)
			{
				LuaPlus::LuaObject	SwearEntry = SwearFilter.GetByIndex(i+1);
				if (SwearEntry.IsTable())
				{
					SwearSet	NewSet;
					// look for
					LuaPlus::LuaObject	SwearSource = SwearEntry.GetByName("From");
					// replace with
					NewSet.To = lang::Lang::ConvertAtoW(ScriptHelper::GetTableString(SwearEntry, "To", "-"));

					if (SwearSource.IsString())
					{
						std::string	From = SwearSource.ToString();
						NewSet.From.push_back(lang::Lang::ConvertAtoW(From));
					} else
					if (SwearSource.IsTable())
					{	
						for (int j=0; j<SwearSource.GetTableCount(); j++)
						{
							LuaPlus::LuaObject	SwearWord = SwearSource.GetByIndex(j+1);
							std::string		From = ScriptHelper::GetString(SwearWord, "");
							if (!From.empty())
							{
								NewSet.From.push_back(lang::Lang::ConvertAtoW(From));
							}	
						}
					}	
					if (!NewSet.From.empty())
					{
						m_SwearFilter.push_back(NewSet);
					}
				}
			}
		}
	}
	LuaPlus::LuaState::Destroy( pScript );

// test-run
	std::string		Fuck = "fucked up and really cuntdsf noob";
	std::string		Test;
	SanitizeA(Fuck, Test);

	return true;
}

void	Swear::SanitizeA(const std::string& Source, std::string& Clean)
{
	std::wstring	From = lang::Lang::ConvertAtoW(Source);
	std::wstring	To;
	SanitizeW(From, To);
	Clean = lang::Lang::ConvertWtoA(To);
}

struct WildCardCompare
{
	bool operator () (const char lhs , const char rhs)
	{
		return tolower(lhs) == tolower(rhs) || rhs == '?';
	}
};

void	Swear::SanitizeW(const std::wstring& Source, std::wstring& Clean)
{
	Clean = Source;
	for (unsigned int i=0; i<m_SwearFilter.size(); i++)
	{
		SwearSet*	pSet = &m_SwearFilter[i];
		for (unsigned int j=0; j<pSet->From.size(); j++)
		{
			std::wstring&			SwearWord = pSet->From[j];

			std::wstring::iterator it = 
				std::search(Clean.begin(), Clean.end(), 
							SwearWord.begin(), SwearWord.end(), WildCardCompare());

			while (it != Clean.end())
			{
				int		From = (int)(it - Clean.begin());
				// we want to seperate the pre-swear word, the post-swear word and insert the To in the middle
				std::wstring		PreSwear = Clean.substr(0, From);
				std::wstring		PostSwear = Clean.substr(From+SwearWord.size(),  Clean.size() - (From+SwearWord.size()));
				Clean = PreSwear + pSet->To + PostSwear;
				// keep looking
				it =  std::search(Clean.begin(), Clean.end(), 
							SwearWord.begin(), SwearWord.end(), WildCardCompare());
			}
		}
	}
}
